﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;

using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Drawing2D;

using cc2530.Lib.contiki;

namespace cc2530.Lib.Draw
{

    /// <summary>
    /// 画图类控件
    /// </summary>
    class NodesPlant : System.Windows.Forms.GroupBox
    {
        private List<NodeView> ListNodeView = new List<NodeView>();


        #region component

        private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
        private System.Windows.Forms.ToolStripMenuItem 显示ToolStripMenuItem;
        private System.Windows.Forms.ToolStripMenuItem 名称ToolStripMenuItem;
        private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
        private System.Windows.Forms.ToolStripMenuItem 连接线ToolStripMenuItem;
        private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
        private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;

        void InitializeComponent()
        { 
            //右键菜单
            this.contextMenuStrip1 = new ContextMenuStrip() ;
            this.显示ToolStripMenuItem = new ToolStripMenuItem();
            this.名称ToolStripMenuItem = new ToolStripMenuItem();
            this.连接线ToolStripMenuItem = new ToolStripMenuItem();
            this.toolStripSeparator1 = new ToolStripSeparator();
            this.toolStripSeparator2 = new ToolStripSeparator();
            this.toolStripSeparator3 = new ToolStripSeparator();
            this.contextMenuStrip1.SuspendLayout();
            this.SuspendLayout();



            // 
            // contextMenuStrip1
            // 
            this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.显示ToolStripMenuItem,
            this.toolStripSeparator1});
            this.contextMenuStrip1.Name = "contextMenuStrip1";
            this.contextMenuStrip1.Size = new System.Drawing.Size(153, 54);
            // 
            // 显示ToolStripMenuItem
            // 
            this.显示ToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.名称ToolStripMenuItem,
            this.toolStripSeparator2,
            this.连接线ToolStripMenuItem,
            this.toolStripSeparator3});
            this.显示ToolStripMenuItem.Name = "显示ToolStripMenuItem";
            this.显示ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.显示ToolStripMenuItem.Text = "显示";
            // 
            // toolStripSeparator1
            // 
            this.toolStripSeparator1.Name = "toolStripSeparator1";
            this.toolStripSeparator1.Size = new System.Drawing.Size(149, 6);
            // 
            // 名称ToolStripMenuItem
            // 
            this.名称ToolStripMenuItem.Name = "名称ToolStripMenuItem";
            this.名称ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.名称ToolStripMenuItem.Text = "名称";
            // 
            // toolStripSeparator2
            // 
            this.toolStripSeparator2.Name = "toolStripSeparator2";
            this.toolStripSeparator2.Size = new System.Drawing.Size(149, 6);
            // 
            // 连接线ToolStripMenuItem
            // 
            this.连接线ToolStripMenuItem.Name = "连接线ToolStripMenuItem";
            this.连接线ToolStripMenuItem.Size = new System.Drawing.Size(152, 22);
            this.连接线ToolStripMenuItem.Text = "连接线";
            // 
            // toolStripSeparator3
            // 
            this.toolStripSeparator3.Name = "toolStripSeparator3";
            this.toolStripSeparator3.Size = new System.Drawing.Size(149, 6);

            this.contextMenuStrip1.ResumeLayout(false);
            ResumeLayout(false);

        }
        #endregion

        #region  属性
        public bool LinesVisable = true;
        public bool NameVisable = true;
        public Color LineColor = Color.Red;
        public Font NameFont = new Font("宋体", 8);
        public Color NameColor = Color.DarkSlateGray;
        #endregion


        #region 构造
        public NodesPlant() : base() {
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                                ControlStyles.ResizeRedraw |
                                ControlStyles.AllPaintingInWmPaint, true);

            InitializeComponent();

            this.ContextMenuStrip = contextMenuStrip1;
        }
        //public NodesPlant(List<contikiNode> nodes) : this() { NodesLocationChanged = true; }
        public void AddNode(NodeView node)
        {
            if (this.ListNodeView == null) { this.ListNodeView = new List<NodeView>(); }
            if (node.Parent != this)
            {
                ListNodeView.Add(node);
                this.Controls.Add(node);
                node.LocationChanged +=node_LocationChanged;
                Refresh();
            }
        }

        void node_LocationChanged(object sender, EventArgs e)
        {
            //位置限定
            NodeView n = sender as NodeView;
            int x = n.Location.X;
            int y = n.Location.Y;
            if (x > this.Width) { x = this.Width; }
            if (x < 0) { x = 0; }
            if (y > this.Height) { y = this.Height; }
            if (y < 0) y = 0;
            n.Location = new Point(x, y);
 	        //throw new NotImplementedException();
            Refresh();
        }     
        public void DeleteNode(NodeView node)
        {
            if (ListNodeView != null)
            {
                foreach (NodeView n in ListNodeView) {
                    if (n == node)
                    {
                        ListNodeView.Remove(node);
                        this.Controls.Remove(n);
                        node.LocationChanged -=node_LocationChanged;
                        Refresh();
                    }
                }
            }

        }
        public void DeleteAllNodes() {
            foreach (NodeView v in ListNodeView) { Controls.Remove(v);v.LocationChanged-=node_LocationChanged;}
            ListNodeView.Clear();
            Refresh();
        }
        #endregion

        #region 显示策略,公布策略
        //显示路由，显示节点，显示 borderrouter
        // n 级 邻居的显示，n 级邻居的线显示
        //数据传送路径显示



        private int FanR = 70;//半径增量
        private int StartArc = 0;//范围
        private int EndArc = 360;
        private Random r = new Random((int)System.DateTime.Now.Ticks);
        private long a = 1;
        private Point FanExpanLocation(int level,Point rootpos)
        {
            //取得度数
            a = r.Next(StartArc*100, EndArc*100)/100;

            int x = (int)(0-System.Math.Cos(a) * FanR * level);
            int y = (int)(0-System.Math.Sin(a) * FanR *level);

            //下一个随机数
            long sd = r.Next(1000, 5000000);
            r = new Random((int)(sd));
            return new Point(rootpos.X + x, rootpos.Y + y);
            
        }


        private void FanExpanNode(NodeView node,int level,Point rootPos) {
            foreach (NodeView n in Neighbor(node))
            {
                n.Location = FanExpanLocation(level, rootPos);
            }
        }

        private void FanExpanAll(NodeView root,int level,Point justPost) {
            FanExpanNode(root,level,justPost);
            foreach (NodeView node in Neighbor(root)) {
                FanExpanAll(node, level + 1,justPost);
            }
        }

        //以扇形分布所有节点
        public void FanExpandAllNodes()
        {
            int level = 1;

            NodeView root = BorderView();
            if(root == null)root= ListNodeView[0];
            root.Location = new Point(this.Width / 2, this.Height / 2);
            FanExpanAll(root, 1,root.Location);
        }
        #endregion

        #region 绘图
        private void DrawLineN2N(NodeView from,NodeView to,Graphics g)
        {
            //计算偏移
            int x = from.Location.X - to.Location.X;
            int y = from.Location.Y - to.Location.Y;
            int l = (int)System.Math.Sqrt(x * x + y * y);
            int Rf = from.Size.Width / 2;
            int Rt = to.Size.Width / 2;
            int xf,yf,xt,yt;xf = yf = xt = yt =0;
            if (l != 0)
            {
                xf = Rf * x / l;
                yf = Rf * y / l;
                xt = Rt * x / l;
                yt = Rt * y / l;
            }
            else { }
            Point f = new Point(from.Location.X + Rf -xf, from.Location.Y + Rf -yf);
            Point t = new Point(to.Location.X + Rt + xt, to.Location.Y + Rf + yt);
            
            //箭头样式
            Pen p = new Pen(LineColor);
            p.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(4, 4, true);
            g.DrawLine(p, f, t);
        }
        private void DrawLineN2Neighbors(NodeView from, Graphics g)
        {
            foreach (contikiNode n in from.Self.Neighbors)
            {
                foreach (NodeView t in this.ListNodeView)
                {
                    //通过名字来识别 节点 
                    if (n.name == t.Name)
                    {
                        DrawLineN2N(from, t, g);
                    }
                }
            }
        }
        private void DrawLineALLNodes(Graphics g)
        {
            foreach(NodeView n in this.ListNodeView) {
                DrawLineN2Neighbors(n,g);
            }
        }
        #endregion

        #region 重载
        protected override void OnPaint(PaintEventArgs e)
        {
            //位置变化，重新画线
            if (LinesVisable == true)
            {
                DrawLineALLNodes(e.Graphics);
            }

            if (NameVisable == true) {
                foreach (NodeView node in ListNodeView) {
                    if (node.Visible) { 
                        //显示name
                        e.Graphics.DrawString(node.Name, this.NameFont, new SolidBrush(NameColor),
                            new PointF(node.Location.X + node.Size.Width, node.Location.Y));
                    }
                }
            }
            base.OnPaint(e);
        }
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            //DrawLineALLNodes(pevent.Graphics);
            base.OnPaintBackground(pevent);
        }  
       
        #endregion



        #region 私有      
        bool IsNeighbor(NodeView node, NodeView neighbor) {
            return node.Self.Neighbors.Contains(neighbor.Self);
        }
        NodeView BorderView() {
            foreach (NodeView n in ListNodeView) { if (n.Self.ntype == NodeType.BorderRouter)return n; }
            return null;
        }
        List<NodeView> Neighbor(NodeView root) {
            List<NodeView> n = new List<NodeView>();
            foreach (NodeView v in ListNodeView)
                if (root.Self.Neighbors.Contains(v.Self))
                    n.Add(v);
            return n;
        }
        #endregion


    }

    //单个控件
    public class NodeView : UserControl
    {
        const int R = 8;
        public contikiNode Self;
        public NodeView()
            : base()
        {
            Size = new Size(R * 2, R * 2);
            BackColor = Color.Transparent;
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                                ControlStyles.ResizeRedraw |
                                ControlStyles.AllPaintingInWmPaint, true);
        }
        public NodeView(contikiNode node) : this() { 
            Self = node;
            Location = node.location;
            Name = node.name;
        }
        
        #region 自定义形状
        //绘图
        protected override void OnPaint(PaintEventArgs e)
        {
            #region  重新设定边界
            GraphicsPath path = new GraphicsPath();
            path.AddEllipse(new Rectangle(0, 0, Size.Width, Size.Height));
            this.Region = new Region(path);
            #endregion
            base.OnPaint(e);
            Graphics g = e.Graphics;

            Pen pen;
            Brush b =Brushes.IndianRed;
            try{
                switch (this.Self.ntype) { 
                    case NodeType.BorderRouter:
                        b = Brushes.Orange;
                        break;
                    case NodeType.Router:
                        b = Brushes.DarkGreen;
                        break;
                    case NodeType.Node:
                        b = Brushes.Blue;
                        break;
                    case NodeType.PCnode:
                        b = Brushes.DodgerBlue;
                        break;
                    default:
                        b = Brushes.Black;
                        break;
                }
            }catch{}

            pen = new Pen(b,2);
            g.DrawEllipse(pen, 0, 0, Size.Width, Size.Height);
            g.FillEllipse(b, 1, 1,Size.Width - 2, Size.Height - 2);
        }
        //背景
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
        }
        
        #endregion


        #region 鼠标拖动
        bool drag = false;
        Point start;
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                drag = true;
                start = MousePosition;
            }
        }
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                drag = false;
            }
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (drag == true)
            {
                Point End = MousePosition;
                int x = End.X - start.X;
                int y = End.Y - start.Y;
                Location = new Point(Location.X + x, Location.Y + y);
                start = End;

            }
            base.OnMouseMove(e);
        }
        #endregion

    }
}

